var net = require('net');
var stream = require('stream')
var tcp_server = net.createServer(); // 创建 tcp server
var process = require('process')
var Sockets = {};
var SocketID = 1;

var WebSockets = {};
var WebSocketID = 1;

function MODBUS_CRC(data) {
    let crcValue = 0xFFFF;
    for (let i = 0; i < data.length; i++) {
        crcValue ^= data[i] & 0xFFFF
        for (let j = 0; j < 8; j++) {
            if (crcValue & 0x0001) {
                crcValue >>= 1
                crcValue ^= 0xA001
            } else {
                crcValue >>= 1
            }
        }
    }

    var buf = Buffer.alloc(2)
    var t = crcValue & 0xFF00
    t = t >> 8
    buf[1] = t
    buf[0] = crcValue & 0xFF

    var val = buf.toString('hex').toUpperCase()
    return val
}

var PumpAddress = {
    '1#': '0000'
}

//施肥机寻址
var ApplyFertilizerValveAddress = {
    '1#': '0001', //施肥启停
    '2#': '0002', //施肥启停
    '3#': '0003', //施肥启停
    '4#': '0004', //施肥启停
    '5#': '0005', //施肥启停
}

//配肥机寻址
var MixFertilizerValveAddress = {
    '1#': '0006', //配肥启停
    '2#': '0007', //配肥启停
}

//节点水流阀门
var WaterValveAddress = {
    '1#-1': '0008',
    '1#-2': '0009',
    '2#-1': '000A',
    '2#-2': '000B',
    '3#-1': '000C',
    '3#-2': '000D',
    '4#-1': '000E',
    '4#-2': '000F',
    '5#-1': '0010',
    '5#-2': '0011',
    '6#-1': '0012',
    '6#-2': '0013',
    '7#-1': '0014',
    '7#-2': '0015',
    '8#-1': '0016',
    '8#-2': '0017',
    '9#-1': '0018',
    '9#-2': '0019',
    '10#-1': '001A',
    '10#-2': '001B',
    '11#-1': '001C',
    '11#-2': '001D',
    '12#-1': '001E',
    '12#-2': '001F',
    '13#-1': '0020',
    '13#-2': '0021',
    '14#-1': '0022',
    '14#-2': '0023',
    '15#-1': '0024',
    '15#-2': '0025',
    '16#-1': '0026',
    '16#-2': '0027',
    '17#-1': '0028',
    '17#-2': '0029',
    '18#-1': '002A',
    '18#-2': '002B',
    '19#-1': '002C',
    '19#-2': '002D',
    '20#-1': '002E',
    '20#-2': '002F',
    '21#-1': '0030',
    '21#-2': '0031',
    '22#-1': '0032',
    '22#-2': '0033',
    '23#-1': '0034',
    '23#-2': '0035',
    '24#-1': '0036',
    '24#-2': '0037',
    '25#-1': '0038',
    '25#-2': '0039',
    '26#-1': '003A',
    '26#-2': '003B',
    '27#-1': '003C',
    '27#-2': '003D',
    '28#-1': '003E',
    '28#-2': '003F',
    '29#-1': '0040',
    '29#-2': '0041',
    '30#-1': '0042',
    '30#-2': '0043',
    '31#-1': '0044',
    '31#-2': '0045',
    '32#-1': '0046',
    '32#-2': '0047',
    '33#-1': '0048',
    '33#-2': '0049',
    '34#-1': '004A',
    '34#-2': '004B',
    '35#-1': '004C',
    '35#-2': '004D',
    '36#-1': '004E',
    '36#-2': '004F',
    '37#-1': '0050',
    '37#-2': '0051',
    '38#-1': '0052',
    '38#-2': '0053',
    '39#-1': '0054',
    '39#-2': '0055',
    '40#-1': '0056',
    '40#-2': '0057',
}

var ValveType = {
    'sb': PumpAddress,
    'sf': ApplyFertilizerValveAddress,
    'pf': MixFertilizerValveAddress,
    'dcf': WaterValveAddress
}

var FlexBuffer = function(buf) {
    this.buf = buf
}

Object.defineProperty(FlexBuffer.prototype, 'length', {
    get: function() {
        return this.buf.length - this.offset
    }
})

FlexBuffer.prototype.buf = null
FlexBuffer.prototype.offset = 0

FlexBuffer.prototype.readUInt16BE = function() {
    var val = this.buf.readInt16BE(this.offset)
    this.offset += 2
    return val
}

FlexBuffer.prototype.readUInt8 = function() {
    var val = this.buf.readUInt8(this.offset)
    this.offset += 1
    return val
}

FlexBuffer.prototype.slice = function(len) {
    var f = new FlexBuffer(this.buf.slice(this.offset, this.offset + len))
    this.offset += len
    return f
}

FlexBuffer.prototype.toString = function(f) {
    return this.buf.slice(this.offset).toString('hex')
}


var HeaderPaser = function(buf) {
    var header = {}

    header.byteLenght = buf.readUInt8() //指令跟随数据字节长度.

    var buf2 = buf.slice(header.byteLenght + 2) //加2字节校验码长度.
    header.type = buf2.readUInt16BE()

    header.pointNum = buf2.readUInt16BE() //有效节点个数
    header.wordLenght = buf2.readUInt16BE() // 有效字个数

    if (header.type == 0x0000) //首部
    {
        header.name = '首部'
        header.main = {}
        header.main.main_pip_press = (buf2.readUInt16BE() / 100).toFixed(3) //主干压力
        header.main.pump_op_state = buf2.readUInt8() //水泵操作状态
        header.main.pump_work_state = buf2.readUInt8() //水泵工作状态
        header.main.main_pip_flow = (buf2.readUInt16BE() / 100).toFixed(3) //主管道流量
        header.main.now_flow_sum = (buf2.readUInt16BE() / 100).toFixed(3) //主管道累计
        header.main.ec_value = buf2.readUInt16BE() //EC实测值
        header.main.total_fei = buf2.readUInt16BE() //总运行区数

        header.main.applyNum = header.pointNum & 0xFF
        header.main.mixNum = (header.pointNum & 0xFF00) >> 8


    } else if (header.type == 0x0001) //节点
    {
        header.name = '节点'
    }
    if (header.pointNum * 4 > buf2.length || header.wordLenght * 2 > buf2.length) return null

    return [header, buf2]
}

//施肥机解析
var ApplyFertilizerPaser = function(buf) {
    var point = {}
    point.work_state = buf.readUInt8() > 0 //施肥开启状态
    point.op_state = buf.readUInt8() > 0 //施肥操作状态
    point.now_flow = (buf.readUInt16BE() / 1000).toFixed(3) //肥管瞬时流量
    point.total_flow = (buf.readUInt16BE() / 100).toFixed(3) //肥管本次累计
    return point
}


var MixFertilizerPaser = function(buf) {
    var point = {}
    point.work_state = buf.readUInt8() > 0 //配肥开启状态
    point.op_state = buf.readUInt8() > 0 //配肥操作状态
    return point
}

var PointPaser = function(buf) {
    var point = {}

    var op_state = buf.readUInt8() //电磁阀操作状态 高位
    point.online = !!buf.readUInt8() //在线状态 低位

    var worker_2 = {}
    var worker_state2 = buf.readUInt8() //电磁阀#2反馈状态
    worker_2.used = worker_state2 != 0xFF //是否使用
    worker_2.worker_state = worker_state2 == 0xFF ? 0 : worker_state2 //工作反馈状态
    worker_2.op_state = (op_state & 0x02) > 0 //操作状态

    var worker_1 = {}
    var worker_state1 = buf.readUInt8() //电磁阀#1反馈状态
    worker_1.used = worker_state1 != 0xFF //是否使用
    worker_1.worker_state = worker_state1 == 0xFF ? 0 : worker_state1 //工作反馈状态
    worker_1.op_state = (op_state & 0x01) > 0 //操作状态

    point.workers = []
    point.workers.push(worker_1)
    point.workers.push(worker_2)

    return point
}

var PackePaser = function(buf) {

    var packe = {}

    if (buf.length < 3) return null

    var direction = buf.slice(2).toString('hex') //指令

    if (direction == '0106') {
        //console.log()
        packe.msg = '收到指令应答:' + direction + buf.toString()
        return packe
    }

    if (direction != '0103') throw new Error('指令头不正确.')

    var [header, buf2] = HeaderPaser(buf)

    packe.header = header

    var points = []

    if (header.type == 0x0000) {
        var applyFertilizers = []
        for (let index = 0; index < header.main.applyNum; index++) {
            var _buf = buf2.slice(6)
            applyFertilizers.push(ApplyFertilizerPaser(_buf))
        }

        packe.applyFertilizers = applyFertilizers


        var mixFertilizers = []
        for (let index = 0; index < header.main.mixNum; index++) {
            var _buf = buf2.slice(2)
            mixFertilizers.push(MixFertilizerPaser(_buf))
        }

        packe.mixFertilizers = mixFertilizers
    } else if (header.type == 0x0001) {
        for (let index = 0; index < header.pointNum; index++) {
            var _buf = buf2.slice(4)
            points.push(PointPaser(_buf))
        }

        packe.points = points
    }

    return packe
}

// while (fbuf.length > 0) {
//     var packe = PackePaser(fbuf)
//     console.log(JSON.stringify(packe))
// }

// 监听 端口


var SocketTypes = {
    normal: 0,
    ctrl: 1,
}

// socket -> websocket | IPC
// 处理每个客户端消息
function DealConnect(socket) {

    socket.on('data', function(data) {
        //data = data.toString();
        // 向所有客户端广播消息
        //for(var i in Sockets){
        //    Sockets[i].write(data);
        //}
        // socket.write(data);
        var buf = new Buffer(data)
        var hexStr = buf.toString('hex')

        console.log(hexStr);

        if (socket.type === undefined) {
            if (hexStr.startsWith('fefe')) {
                socket.type = SocketTypes.normal
                console.log('##数据站点模块连接.');
            } else if (hexStr.startsWith('fffe')) {
                socket.type = SocketTypes.ctrl
                console.log('##控制站点模块连接.');
            }

            return
        } else {
            //console.log('收到数据-Type:' + socket.type)
            for (const key in Sockets) {
                var s = Sockets[key]

                if (s.id == socket.id)
                    continue

                s.write(buf)
            }

            try {
                var packe = PackePaser(new FlexBuffer(buf))
            } catch (e) {
                console.log(e)
                return
            }

            for (const key in WebSockets) {
                var ws = WebSockets[key]

                //if (s.id == ws.id)
                //    continue
                ws.send(JSON.stringify(packe))
            }

            process.send(packe)
        }

    })

    // 客户端正常断开时执行
    socket.on('close', function() {
            console.log('client disconneted!');
        })
        // 客户端正异断开时执行
    socket.on("error", function(err) {
        console.log('client error disconneted!');
    });
}


//export default function () {

let port = process.env.LISTEN

try {
    tcp_server.listen(parseInt(port), '0.0.0.0', function() {
        console.log('tcp_server listening:' + port);
    });
} catch (e) {
    console.log(e)
    exit(1)
}

// 处理客户端连接
tcp_server.on('connection', function(socket) {
    console.log(socket.address());
    Sockets[SocketID] = socket;
    socket.id = SocketID
    SocketID++;
    DealConnect(socket)

    //process.send('HAHA,hello!')
})

tcp_server.on('error', function() {
    console.log('tcp_server error!');
})

tcp_server.on('close', function() {
    console.log('tcp_server close!');
})

function handleWSMessage(message, cb) {
    //打印客户端监听的消息
    //console.log(message)

    if (!message.startsWith('@')) {
        console.log('获取到非指令消息:' + message)
        return
    }

    var direction = message.substr(1)

    cb('收到指令' + direction)
    direction = direction.split(':')

    var t = '0106'

    try {

        if (direction.length != 3)
            throw new Error('命令格式不正确.')

        var valveAddress = ValveType[direction[1]]

        if (valveAddress === undefined)
            throw new Error('命令指定设备类型不正确.')

        var serise = direction[2]
        var addr = valveAddress[serise]

        if (addr == undefined)
            throw new Error('无法获取设备地址:' + serise)

        t += addr

        if (direction[0] == 'open') {
            t += '0001'
        } else if (direction[0] == 'close') {
            t += '0000'
        } else {
            throw new Error('无法识别命令:' + direction[0])
        }

        var crc = MODBUS_CRC(Buffer.from(t, "hex"))
        t += crc


    } catch (e) {
        cb('失败:' + message)
        cb('错误:' + e.message)
        return
    }

    var buf = Buffer.from(t, 'hex')

    for (const key in Sockets) {
        var s = Sockets[key]

        //if (s.type === SocketTypes.normal)
        s.write(buf)
    }

    cb('成功2:' + message)
    cb('指令:' + t)
}

// var WebSocketServer = require('ws').Server;
// const { exit } = require('process');

// var wss = null

// try {
//     wss = new WebSocketServer({ port: parseInt(port) + 10000 }); //服务端口8181  
// } catch (e) {
//     console.log(e)
//     exit(1)
// }

// wss.on('connection', function(ws) {
//     console.log('服务端：客户端已连接');

//     ws.id = WebSocketID
//     WebSockets[WebSocketID] = ws
//     WebSocketID++

//     ws.on('message', function(message) {
//         let ret = handleWSMessage(message, (msg) => {
//             ws.send(msg)
//         })
//     });
// });

//IPC -> socket
process.on('message', function(message) {
    console.log(message)
    let ret = handleWSMessage(message, (msg) => {
        process.send(msg)
    })
})

process.on('disconnect', function() {
    try {
        wss.close()
        tcp_server.close()
    } catch (e) {
        exit(0)
    }
})